#include "EstrategiaBloques.h"

EstrategiaBloques::EstrategiaBloques(Almacenamiento **persistencia,TipoAlmacenamiento tipo){

	this->posIni=0;
	this->offset=0;
	this->tipoA = tipo;
	this->persistencia = persistencia;
	
}

void EstrategiaBloques::actulizarEspLibres(Compuesto *compuesto){

	vector<unsigned int>::iterator it;
	int i;
	unsigned int esp;
	Bloque *b;
	
	Buffer::getInstance()->getListEspaciosLibres()->clear();
	
	for (i=0; i<compuesto->getCantidadComponentes(); i++){
		b= (Bloque*)compuesto->getComponenteAt(i);
		esp=b->getTamanioLibre();
		Buffer::getInstance()->getListEspaciosLibres()->push_back(esp);
	}

}
		
void EstrategiaBloques::cargaInicialB(vector<Dato*> listaDatos){
	
	Compuesto *compuesto= this->persistencia[0]->getCompuesto();
	Bloque *bqmem;
	int i=0;
	RegistroMemoria *reg;
	void *pos= Buffer::getInstance()->getPointer();
	unsigned int tam, offset=0;
	
	bqmem=(Bloque*)compuesto->getComponenteAt(i);
	vector<Dato*>::iterator it;
	for (it= listaDatos.begin(); it != listaDatos.end(); it++){
		
		tam= (*it)->getTamanio(BINARIO);
		reg= new RegistroMemoria(this->tipoMem, tam, pos, *it);
		pos= (char*)pos + tam ; 
		offset+=tam;
		if (bqmem->getTamanioLibre() < tam){
			offset=0;
			i++;
			try{
			bqmem=(Bloque*)compuesto->getComponenteAt(i);
			} 
			catch (exception *e){
				throw e;
			}
		}
		((BloqueMemoria*)bqmem)->addComponente(reg);
	}
	
}

void EstrategiaBloques::cargaInicialD(vector<Dato*> listaDatos){

	Compuesto *compuesto= this->persistencia[0]->getCompuesto();
	Bloque *bqd;
	int i=0;
	RegistroDisco *reg;
	void *pos= this->posIni;
	unsigned int tam;
	FILE* fp= (FILE*)pos;
	fseek(fp,0,SEEK_SET);
		
	bqd=(Bloque*)compuesto->getComponenteAt(i);
	vector<Dato*>::iterator it;
	for (it= listaDatos.begin(); it != listaDatos.end(); it++){
		
		tam= (*it)->getTamanio(BINARIO);
		reg= new RegistroDisco(this->tipoMem, tam, fp, *it);
		pos= (char*)pos + tam ;
		fp=(FILE*)pos;
		fseek(fp,this->offset,SEEK_CUR);
		this->offset+=tam;
		if (bqd->getTamanioLibre() < tam){
			i++;
			bqd= new BloqueDisco(this->tipoMem, Buffer::tamanioBloque, fp ,i);
			compuesto->addComponente(bqd);
		}
		
		((BloqueDisco*)bqd)->addComponente(reg);			
	}

}
		
void EstrategiaBloques::crear(TipoMemoria tipo, std::vector<Dato*> listaDatos, void *ptr){

	unsigned int i;
	unsigned int cBloques,cantidadBloques;
	Compuesto *compuesto;
	BloqueMemoria *bqm;
	BloqueDisco *bqd;
	this->posIni = ptr;
	void *posAux;

	if (this->tipoA== BUFFER || this->tipoA == AMBOS){
        posAux = Buffer::getInstance()->getPointer();              
		cBloques= Buffer::getInstance()->getTamanio()/Buffer::tamanioBloque; 
		compuesto= this->persistencia[0]->getCompuesto();
		cantidadBloques=0;
		for (i=0; i<cBloques; i++){
		
			bqm= new BloqueMemoria(tipo, Buffer::tamanioBloque, i,posAux);
			compuesto->addComponente(bqm);
			cantidadBloques++;
			posAux = (char*)Buffer::getInstance()->getPointer() + Buffer::tamanioBloque;
		}
		EstrategiaBloques::cargaInicialB(listaDatos);
		this->persistencia[0]->salvarTodo(BINARIO);
	}
	if (this->tipoA== ARCHIVO || this->tipoA == AMBOS){
        posAux = this->posIni;
		compuesto= this->persistencia[1]->getCompuesto();
		bqd= new BloqueDisco(tipo, Buffer::tamanioBloque, (FILE*)ptr ,0);
		compuesto->addComponente(bqm);
		EstrategiaBloques::cargaInicialD(listaDatos);
		this->persistencia[1]->salvarTodo(BINARIO);
	}
	
	actulizarEspLibres(compuesto);

}


		
void EstrategiaBloques::insertar(Dato *dato, int* nroComponente){
        Bloque *b;
        bool esp=false;
        Compuesto *compuesto;
         void* pos;
         Registro *reg;
        int i=0;
        if(*nroComponente==-1){
             if (this->tipoA== BUFFER || this->tipoA == AMBOS){
                    compuesto= this->persistencia[0]->getCompuesto();           
          
                    for(i=0;i<compuesto->getCantidadComponentes();i++){
                            if(((Bloque*)compuesto->getComponenteAt(i))->getTamanioLibre() >= dato->getTamanio(BINARIO)){
                                  esp= true;
                                  break;
                            }
                    }                                                
                    //puede q entre en el ultimo y yo lo este emtiendo en un componente nuevo... x eso "esp"                       
                    if(i==compuesto->getCantidadComponentes() &&  ( !esp )){
                           pos = (char*)Buffer::getInstance()->getPointer() + this->offset;                                                               
                           b = new BloqueMemoria(this->tipoMem,Buffer::tamanioBloque, i, pos);
                           this->offset += dato->getTamanio(BINARIO);   
                           compuesto->addComponente(b);                                         
                    }
                    (*nroComponente) = i;              
             }
             if (this->tipoA== ARCHIVO || this->tipoA == AMBOS){
                               // mismo pero con disco
                compuesto= this->persistencia[0]->getCompuesto();           
    
                for(i=0;i<compuesto->getCantidadComponentes();i++){
                      if(((Bloque*)compuesto->getComponenteAt(i))->getTamanioLibre() >= dato->getTamanio(BINARIO))
                      break;
                }                                                                       
                if(i==compuesto->getCantidadComponentes()){
                      FILE* fp = (FILE*)pos;                                      
                      fseek(fp, this->offset, SEEK_CUR);                  
                      b = new BloqueDisco(this->tipoMem,Buffer::tamanioBloque, fp,i);
                      this->offset += dato->getTamanio(BINARIO);   
                      compuesto->addComponente(b);                                         
                }
                (*nroComponente) = i;       
                   
             }                           
        }
       
       	if (this->tipoA== BUFFER || this->tipoA == AMBOS){
        	compuesto= this->persistencia[0]->getCompuesto();
        	
        	try{
        	b = (Bloque*)compuesto->getComponenteAt(*nroComponente);
        	}catch (exception *e){
				throw e;
			}
        	pos = (char*)Buffer::getInstance()->getPointer() + this->offset;
        	
     	  	reg= new RegistroMemoria(this->tipoMem, dato->getTamanio(BINARIO), pos, dato);
        	b->addComponente(reg);
        	reg->escribir(BINARIO);   
        	actulizarEspLibres(compuesto);
        	this->offset += dato->getTamanio(BINARIO);
		}
		if (this->tipoA== ARCHIVO || this->tipoA == AMBOS){
			compuesto= this->persistencia[1]->getCompuesto();
        	
        	try{
        	b = (Bloque*)compuesto->getComponenteAt(*nroComponente);
        	}catch (exception *e){
				throw e;
			}
        	FILE*fp = (FILE*)pos;
        	fseek(fp, this->offset, SEEK_SET);         
        	reg= new RegistroDisco(this->tipoMem, dato->getTamanio(BINARIO), fp, dato);
        	b->addComponente(reg);
        	reg->escribir(BINARIO);        	
        	actulizarEspLibres(compuesto);
        	this->offset += dato->getTamanio(BINARIO);
		}
}
		
void EstrategiaBloques::leer(Dato *dato, int nroBloque){

	Bloque *compuesto;
	Compuesto *compuestoAux;
	unsigned int tam, pos;
	Registro *raux;

	if (this->tipoA== BUFFER || this->tipoA == AMBOS){
       	compuestoAux= this->persistencia[0]->getCompuesto();
       	compuesto=(Bloque*)compuestoAux->getComponenteAt(nroBloque);
       	ubicar(compuesto,dato,&pos, &tam,BINARIO);
		raux=(RegistroMemoria*)compuesto->getComponenteAt(pos);
		((RegistroMemoria*)raux)->leer(dato,BINARIO);
    	return;     
	}
	if (this->tipoA== ARCHIVO/* || this->tipoA == AMBOS*/){ 
		compuestoAux= this->persistencia[1]->getCompuesto();
       	compuesto=(Bloque*)compuestoAux->getComponenteAt(nroBloque);
       	ubicar(compuesto,dato,&pos, &tam,BINARIO);
		raux=(RegistroDisco*)compuesto->getComponenteAt(pos);
		((RegistroDisco*)raux)->leer(dato,BINARIO);
	}
}
		
void EstrategiaBloques::modificar(Dato *daux, int bOrig,  int *bDest){
   unsigned int pos;
   unsigned int tam;
   void *posAux;
   Bloque *b;
   Compuesto *compuesto;
   Registro *reg;
   try{     
        if (this->tipoMem== FIJA){
           if(this->tipoA==BUFFER || this->tipoA==AMBOS){  
                compuesto= this->persistencia[0]->getCompuesto();                                
                b = (Bloque*)compuesto->getComponenteAt(bOrig);                  
                ubicar(b, daux,&pos, &tam,BINARIO);
                reg=(RegistroMemoria*)b->getComponenteAt(pos);
                reg->getAccesoDato(&posAux);//
                reg->escribir(posAux,daux,BINARIO);
           }                            
           if(this->tipoA==ARCHIVO || this->tipoA==AMBOS){  
                compuesto= this->persistencia[1]->getCompuesto();                  
                b = (Bloque*)compuesto->getComponenteAt(bOrig);                  
                ubicar(b, daux,&pos, &tam,BINARIO);
                reg=(RegistroMemoria*)b->getComponenteAt(pos);
                reg->getAccesoDato(&posAux);//
                reg->escribir(posAux,daux,BINARIO);
           }                                                        
           *bDest = bOrig;                 
           return;                 
        }        
        // si llega aca es variable
        this->eliminar(daux,bOrig);
        this->insertar(daux, bDest);
     }    
     catch(exception *e){
         throw e;
     }
     
     actulizarEspLibres(compuesto);
}
		
void EstrategiaBloques::eliminar(Dato *daux, int nroComponente){
	
	Bloque *compuesto;
	Compuesto *compuestoAux;
	unsigned int tam, pos;
	Registro *reg;
	int i;
	void *posAux;
	 ///ACA PUEDO PONER UN FOR 1 O 2...	 XQ ES LO MISMO	
	if (this->tipoA== BUFFER || this->tipoA == AMBOS){
        	compuestoAux= this->persistencia[0]->getCompuesto();
        	compuesto=(Bloque*)compuestoAux->getComponenteAt(nroComponente);
        	ubicar(compuesto,daux,&pos, &tam,BINARIO);
			reg = (Registro*)compuesto->getComponenteAt(pos);
			reg->borrar();
			compuesto->deleteComponentAt(pos);
			for(i=pos;i<compuesto->getCantidadComponentes();i++){
				reg = (Registro*)compuesto ->getComponenteAt(i);
				reg->getAccesoDato(&posAux);//
				posAux = (char*) posAux -tam;
				reg->escribir(posAux,BINARIO);
			}
        	     
	}
	if (this->tipoA== ARCHIVO || this->tipoA == AMBOS){
		compuestoAux= this->persistencia[1]->getCompuesto();
       	compuesto=(Bloque*)compuestoAux->getComponenteAt(nroComponente);
        ubicar(compuesto,daux,&pos, &tam,BINARIO);
			reg = (Registro*)compuesto->getComponenteAt(pos);
			reg->borrar();
			compuesto->deleteComponentAt(pos);
			for(i=pos;i<compuesto->getCantidadComponentes();i++){
				reg = (Registro*)compuesto ->getComponenteAt(i);
				reg->getAccesoDato(&posAux);//
				posAux = (char*) posAux -tam;
				reg->escribir(posAux,BINARIO);
			}	
	}
	actulizarEspLibres(compuestoAux);

}

void EstrategiaBloques::buscar(Dato *dato,int *nroReg, int nroBloque, unsigned long int clave,TipoSerializacion tipoSerializacion,PrimaryKey *PK){
     Compuesto *compuestoAux;
     if (this->tipoA== BUFFER)
         compuestoAux= this->persistencia[0]->getCompuesto();                   
     else
         compuestoAux= this->persistencia[1]->getCompuesto();                   
     Bloque *compuesto = (Bloque*) compuestoAux->getComponenteAt(nroBloque);
     int i;
     for(i=0;i<compuesto->getCantidadComponentes();i++){
         //Dato *datoAux;
         //datoAux=dato->getNewInstance();//revisar
         char	*datoSerializado=(char*)malloc(dato->getTamanio(BINARIO));
        
         compuesto->getComponenteAt(i)->leer(&datoSerializado,tipoSerializacion);                                               
         //datoAux->serialize(&datoSerializado,tipoSerializacion);
         unsigned long int claveAux;
         int aux;
         char *strClave = PK->GetKey((char*)datoSerializado,aux);
         claveAux = (unsigned long int) atol(strClave);  
         //free(datoSerializado);
         if(claveAux==clave){
         	/**
         	 * evaluar este clone!
         	 * */
              //datoAux->clone(*dato);      
              *nroReg=i;
              return;             
         }
     }   
     //*dato=NULL;
     *nroReg=-1;
}

EstrategiaBloques::~EstrategiaBloques(){

}
